package cn.org.xiaosheng.JUC.synchronizedTest;

import java.util.LinkedList;
import java.util.Random;

public class WaitNotifyDemo {
    // 共享缓冲区
    private static class Buffer {
        private final LinkedList<Integer> queue = new LinkedList<>();
        private final int maxSize = 5; // 缓冲区最大容量

        public synchronized void produce(int value) throws InterruptedException {
            while (queue.size() == maxSize) { // 用while防止虚假唤醒[1,6](@ref)
                System.out.println("缓冲区已满，生产者等待...");
                wait(); // 释放锁并等待
            }
            queue.add(value);
            System.out.println("生产者生产：" + value + "，当前缓冲区大小：" + queue.size());
            // 如果调用 notifyAll() 时没有线程在等待该对象的锁，该方法会“静默”完成，不会抛出异常，也不会影响后续代码的执行
            notifyAll(); // 唤醒所有等待的消费者[7,8](@ref)
        }

        public synchronized int consume() throws InterruptedException {
            while (queue.isEmpty()) { // 用while检查条件[2,5](@ref)
                System.out.println("缓冲区为空，消费者等待...");
                wait();
            }
            int value = queue.removeFirst();
            System.out.println("消费者消费：" + value + "，剩余缓冲区大小：" + queue.size());
            // 如果调用 notifyAll() 时没有线程在等待该对象的锁，该方法会“静默”完成，不会抛出异常，也不会影响后续代码的执行
            notifyAll(); // 唤醒所有等待的生产者
            return value;
        }
    }

    // 生产者线程
    private static class Producer implements Runnable {
        private final Buffer buffer;
        private final Random random = new Random();

        public Producer(Buffer buffer) {
            this.buffer = buffer;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    buffer.produce(i);
                    Thread.sleep(random.nextInt(500)); // 模拟生产耗时
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    // 消费者线程
    private static class Consumer implements Runnable {
        private final Buffer buffer;
        private final Random random = new Random();

        public Consumer(Buffer buffer) {
            this.buffer = buffer;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    buffer.consume();
                    Thread.sleep(random.nextInt(1000)); // 模拟消费耗时
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    // 主测试方法
    public static void main(String[] args) {
        Buffer buffer = new Buffer();
        Thread producer = new Thread(new Producer(buffer), "生产者");
        Thread consumer = new Thread(new Consumer(buffer), "消费者");

        producer.start();
        consumer.start();
    }
}
